import useOnUpdated from "@/lib/hooks/useOnUpdated";
import type { IDeviceStatus, ILimitWarning, IProgramStatus } from "@/lib/types";
import { Button, Table } from "antd";
import { useMemo, useState, type PropsWithChildren } from "react";
import getKey from "./getKey";
import clsm from "@/lib/utils/clsm";

type SelectableColumn = "segment" | "step";

type SelectedData =
  | {
      type: "segment";
      key: number;
    }
  | {
      type: "step";
      key: string;
    };

type ProgramStatusProps = {
  data: IProgramStatus[];
  device?: IDeviceStatus;
  loading?: boolean;
  editable?: boolean;
  advanced?: boolean;
  limits?: Partial<ILimitWarning>;
  onEditRecords?: (
    row: IProgramStatus[],
    column: "循环" | "时间" | "温度" | "湿度" | "压力" | "TS",
  ) => void;
  selectable?: SelectableColumn[];
  onSelectionChange?: (
    data: { type: SelectableColumn; records: IProgramStatus[] } | null,
  ) => void;
};

export default function ProgramStatus(props: ProgramStatusProps) {
  const {
    loading,
    data,
    device,
    editable,
    advanced,
    limits,
    onEditRecords,
    selectable = [],
    onSelectionChange,
  } = props;
  const [selected, setSelected] = useState<SelectedData>();

  const { rowsMap, leadings } = useMemo(() => {
    const rowsMap = new Map<string | number, number>();
    const leadings = new Set<number | string>();
    data.forEach((item) => {
      const no = item.segmentNo;
      const loop = `${item.segmentNo}-${item.segmentLoop}`;
      if (!rowsMap.has(no)) {
        leadings.add(getKey(item));
        rowsMap.set(no, 1);
      } else {
        rowsMap.set(no, rowsMap.get(no)! + 1);
      }
      if (!rowsMap.has(loop)) {
        leadings.add(getKey(item));
        rowsMap.set(loop, 1);
      } else {
        rowsMap.set(loop, rowsMap.get(loop)! + 1);
      }
    });

    return { rowsMap, leadings };
  }, [data]);

  useOnUpdated(() => {
    // if (!)
    setSelected(undefined);
    onSelectionChange?.(null);
  }, [data]);

  const stepSelectable = selectable.includes("step");
  const segmentSelectable = selectable.includes("segment");

  return (
    <Table
      loading={loading}
      dataSource={data}
      rowKey={getKey}
      pagination={false}
    >
      <Table.Column
        title="段"
        dataIndex="segmentNo"
        onCell={(row) => {
          if (leadings.has(getKey(row as IProgramStatus))) {
            return {
              rowSpan: rowsMap.get(row.segmentNo),
              className:
                selected?.type === "segment" && selected?.key === row.segmentNo
                  ? "!bg-blue-800"
                  : "",
              onClick() {
                if (segmentSelectable) {
                  setSelected({ type: "segment", key: row.segmentNo });
                  if (onSelectionChange) {
                    onSelectionChange({
                      type: "segment",
                      records: data.filter(
                        (item) => item.segmentNo === row.segmentNo,
                      ),
                    });
                  }
                }
              },
            };
          }
          return { rowSpan: 0 };
        }}
      />
      <Table.Column
        title="步"
        dataIndex="stepNo"
        onCell={(row) => {
          return {
            className:
              selected?.type === "step" &&
              selected?.key === `${row.segmentNo}-${row.stepNo}`
                ? "!bg-blue-800"
                : "",
            onClick() {
              if (stepSelectable) {
                setSelected({
                  type: "step",
                  key: `${row.segmentNo}-${row.stepNo}`,
                });
                if (onSelectionChange) {
                  onSelectionChange({
                    type: "step",
                    records: [row as IProgramStatus],
                  });
                }
              }
            },
          };
        }}
      />
      <Table.Column
        title="循环"
        onCell={(row) => {
          if (leadings.has(getKey(row as IProgramStatus))) {
            return {
              rowSpan: rowsMap.get(`${row.segmentNo}-${row.segmentLoop}`),
            };
          }
          return { rowSpan: 0 };
        }}
        render={(row) => (
          <EditableCell
            editable={editable}
            onEdit={() =>
              onEditRecords?.(
                data.filter(
                  (item) =>
                    item.segmentNo === row.segmentNo &&
                    item.segmentLoop === row.segmentLoop,
                ),
                "循环",
              )
            }
          >
            {row.segmentLoop}
          </EditableCell>
        )}
      />
      <Table.Column
        title="时间"
        render={(row) => (
          <EditableCell
            editable={editable}
            onEdit={() => onEditRecords?.([row], "时间")}
          >
            {getTime(row)}
          </EditableCell>
        )}
      />
      {(!device || device.isTemperature) && (
        <>
          {advanced && (
            <Table.Column
              title="上下限(温度)"
              render={(row) =>
                row.stepIsT === "1" && (
                  <>
                    升：{row.stepTSv + limits!.tWarningLimitUpper!}&nbsp;℃
                    <br />
                    降：{row.stepTSv - limits!.tWarningLimitLower!}&nbsp;℃
                  </>
                )
              }
            />
          )}
          <Table.Column
            title="步状态"
            render={(row) => <div>{row.tTrend}</div>}
          />
          <Table.Column
            title="温度"
            render={(row) => (
              <EditableCell
                editable={editable}
                onEdit={() => onEditRecords?.([row], "温度")}
              >
                {row.stepIsT === "0" ? (
                  "OFF"
                ) : (
                  <div>
                    {row.stepTSv}&nbsp;℃
                    <br />
                    <span
                      className={clsm(
                        row.stepTIsRate === "1"
                          ? "text-green-500"
                          : "text-red-500",
                      )}
                    >
                      斜率: {row.stepTIsRate === "1" ? "ON" : "OFF"}
                    </span>
                    {/* <br />
            {row.stepTRateValue} */}
                  </div>
                )}
              </EditableCell>
            )}
          />
        </>
      )}
      {(!device || device.isHumidity) && (
        <>
          {advanced && (
            <Table.Column
              title="上下限(湿度)"
              render={(row) =>
                row.stepIsH === "1" && (
                  <>
                    升：{row.stepHSv + limits!.hWarningLimitUpper!}&nbsp;%
                    <br />
                    降：{row.stepHSv - limits!.hWarningLimitLower!}&nbsp;%
                  </>
                )
              }
            />
          )}
          <Table.Column
            title="湿度"
            render={(row) => (
              <EditableCell
                editable={editable}
                onEdit={() => onEditRecords?.([row], "湿度")}
              >
                {row.stepIsH === "0" ? (
                  "OFF"
                ) : (
                  <div>
                    {row.stepHSv}&nbsp;%
                    <br />
                    <span
                      className={clsm(
                        row.stepHIsRate === "1"
                          ? "text-green-500"
                          : "text-red-500",
                      )}
                    >
                      斜率: {row.stepHIsRate === "1" ? "ON" : "OFF"}
                    </span>
                    {/* <br />
              {row.stepHRateValue} */}
                  </div>
                )}
              </EditableCell>
            )}
          />
        </>
      )}
      {(!device || device.isPressure) && (
        <>
          {advanced && (
            <Table.Column
              title="上下限(压力)"
              render={(row) =>
                row.stepIsP === "1" && (
                  <>
                    升：{row.stepPSv + limits!.pWarningLimitUpper!}&nbsp;
                    {row.stepPUnit === 1 ? "Pa" : "kPa"}
                    <br />
                    降：{row.stepPSv - limits!.pWarningLimitLower!}&nbsp;
                    {row.stepPUnit === 1 ? "Pa" : "kPa"}
                  </>
                )
              }
            />
          )}
          <Table.Column
            title="压力"
            render={(row) => (
              <EditableCell
                editable={editable}
                onEdit={() => onEditRecords?.([row], "压力")}
              >
                {row.stepIsP === "0" ? (
                  "OFF"
                ) : (
                  <div>
                    {row.stepPSv}&nbsp;
                    {row.stepPUnit === 1 ? "Pa" : "kPa"}
                    <br />
                    <span
                      className={clsm(
                        row.stepPIsRate === "1"
                          ? "text-green-500"
                          : "text-red-500",
                      )}
                    >
                      斜率: {row.stepPIsRate === "1" ? "ON" : "OFF"}
                    </span>
                    {/* <br />
            {row.stepPRateValue} */}
                  </div>
                )}
              </EditableCell>
            )}
          />
        </>
      )}
      {/* <Table.Column
        title="TS"
        render={(row) => (
          <EditableCell
            editable={editable}
            onEdit={() => onEditRecords?.([row], "TS")}
          >
            {row.stepTs}
          </EditableCell>
        )}
      /> */}
    </Table>
  );
}

type EditableCellProps = PropsWithChildren<{
  editable?: boolean;
  onEdit?: () => void;
}>;
function EditableCell(props: EditableCellProps) {
  const { editable, onEdit, children } = props;
  if (!editable) {
    return children;
  }
  return (
    <Button type="text" onClick={onEdit}>
      {children}
    </Button>
  );
}

function padStart(input: any, len = 2, char = "0") {
  return String(input).padStart(len, char);
}
function getTime(row: IProgramStatus) {
  return `${padStart(row.stepHour)}:${padStart(row.stepMinute)}:${padStart(row.stepSecond)}`;
}
